<?php

    /**
     * Abstract
     *
     * @package      Core
     * @subpackage   Controller_Request
     *
     * @license      GNU Lesser General Public Licence see LICENCE-LGPL file or http://www.gnu.org/licenses/lgpl.html
     */
    abstract class Core_Controller_Request_Abstract extends Core_Object
    {

    ////////////////////////////////////////////////////////////////////////////
	//                                Variables                               //
	////////////////////////////////////////////////////////////////////////////

        /**
         * The path to the entry point in the url
         * if the url is /foo/index.php/bar, its value is /foo/index.php
         *
         * @var string
         */
        protected $_urlScript = '';

        /**
         * The name of the entry point
         * if the url is /foo/index.php/bar, its value is index.php
         *
         * @var string
         */
        protected $_urlScriptName = '';

        /**
         * The path of the entry point in the url
         * if the url is /foo/index.php/bar, its value is /foo/
         *
         * @var string
         */
        protected $_urlScriptPath = '';

        /**
         * The pathinfo part of the url
         * if the url is /foo/index.php/bar, its value is /bar
         *
         * @var string
         */
        protected $_urlPathInfo = '';

        /**
         * Instance parameters
         *
         * @var array
         */
        protected $_params = array();

        /**
         * The request type code
         *
         * @var string
         */
        protected $_type = '';

        /**
         * The type of the default response
         *
         * @var string
         */
        protected $_defaultResponseType = '';

		/**
		 * Zend_Registry object
		 *
		 * @var Zend_Registry
		 */
		protected $_registry = null;

		/**
		 * Core_Controller_Coordinator object
		 *
		 * @var Core_Controller_Coordinator
		 */
		protected $_coordinator = null;

	////////////////////////////////////////////////////////////////////////////
	//                            Getters / Setters                           //
	////////////////////////////////////////////////////////////////////////////

        /**
         * Returns the path to the entry point in the url.
         * If the url is /foo/index.php/bar, its value is /foo/index.php
         *
         * @return      string
         */
        public function getUrlScript()
        {
            return $this->_urlScript;
        }

        /**
         * Returns the name of the entry point.
         * If the url is /foo/index.php/bar, its value is index.php
         *
         * @return      string
         */
        public function getUrlScriptName()
        {
            return $this->_urlScriptName;
        }

        /**
         * Returns the path of the entry point in the url.
         * If the url is /foo/index.php/bar, its value is /foo/
         *
         * @return      string
         */
        public function getUrlScriptPath()
        {
            return $this->_urlScriptPath;
        }

        /**
         * Sets the path of the entry point in the url
         *
         * @param       string      $value
         * @throws      Core_ArgumentException
         * @throws      Core_ArgumentNullException
         * @return      Core_Controller_Request_Abstract
         * @internal    only called in test suite
         */
        public function setUrlScriptPath($value)
        {
            if ($value === null) {
                throw new Core_ArgumentNullException('value is a null reference');
			}

            if (strlen(trim($value)) == 0) {
				throw new Core_ArgumentException('value is a zero-length string');
			}

            $this->_urlScriptPath = $value;
            return $this;
        }

        /**
         * Returns the pathinfo part of the url.
         * If the url is /foo/index.php/bar, its value is /bar
         *
         * @return      string
         */
        public function getUrlPathInfo()
        {
            return $this->_urlPathInfo;
        }

        /**
         * Gets the value of a request parameter. If not defined, gets its default value
         *
         * @param        string      $param : the name of the request parameter
         * @param        mixed       $defaultValue : the default returned value if the parameter doesn't exists
         * @param        boolean     $useDefaultIfEmpty : true: says to return the default value if the parameter value is ""
         * @throws		 Core_ArgumentNullException
         * @return       mixed       the request parameter value
         */
        public function getParam($param, $defaultValue = null, $useDefaultIfEmpty = false)
        {
            if ($param === null) {
				throw new Core_ArgumentNullException('param is a null reference');
			}

            if (isset($this->_params[$param])) {
                if ($useDefaultIfEmpty && trim($this->_params[$param]) == '') {
                    return $defaultValue;
                } else {
                    return $this->_params[$param];
                }
            } else {
                return $defaultValue;
            }
        }

        /**
         * Gets all parameters
         *
         * @return       array
         */
        public function getParams()
        {
            return $this->_params;
        }

        /**
         * Sets one parameter
         *
         * @param       string      $key :   key of the parameter
         * @param       string      $value : value of the parameter
         * @return      Core_Controller_Request_Abstract
         */
        public function setParam($key, $value)
        {
            $this->_params[$key] = $value;
            return $this;
        }

        /**
         * Sets all parameters
         *
         * @param       array       $value : array of parameters
         * @return      Core_Controller_Request_Abstract
         * @internal    only called in test suite
         */
        public function setParams(array $value)
        {
            $this->_params = $value;
            return $this;
        }

        /**
         * Returns the request type code
         *
         * @return      string
         */
        public function getType()
        {
            return $this->_type;
        }

        /**
         * Sets the request type code
         *
         * @param       string      $value
         * @throws      Core_ArgumentException
         * @throws      Core_ArgumentNullException
         * @return      Core_Controller_Request_Abstract
         * @internal    only called in test suite
         */
        public function setType($value)
        {
            if ($value === null) {
                throw new Core_ArgumentNullException('value is a null reference');
			}

            if (strlen(trim($value)) == 0) {
				throw new Core_ArgumentException('value is a zero-length string');
			}

            $this->_type = $value;
            return $this;
        }

        /**
         * Returns the default response type
         *
         * @return      string
         */
        public function getDefaultResponseType()
        {
            return $this->_defaultResponseType;
        }

        /**
         * Gets a response object
         *
         * @param       string      $type  : the type of the response type (ex: "http")
         * @throws      Core_Exception
         * @return      Core_Controller_Response_Abstract   the response object
         */
        public function getResponse($type = '')
        {
            if ($type == '') {
                $type = $this->_defaultResponseType;
            }

            $responseClass = 'Core_Controller_Response_' . ucfirst(strtolower($type));

			if (!$this->isAllowedResponse($responseClass)) {
				throw new Core_Exception('Response type not allowed');
			}

            $response = new $responseClass();

            if ($this->_coordinator instanceof Core_Controller_Coordinator) {
                $this->_coordinator->setResponse($response);
            }

            return $response;
        }

	////////////////////////////////////////////////////////////////////////////
	//                                 Methods                                //
	////////////////////////////////////////////////////////////////////////////

        /**
         * Constructor
         */
        public function __construct()
        {
        }

        /**
         * Destructor
         */
        public function __destruct()
        {
            unset($this);
        }

        /**
         * Initializes the request : analyse of http request etc..
         *
         * @return      void
         */
        public function init()
        {
            $this->_registry	= Zend_Registry::getInstance();
            $this->_coordinator	= Core_Controller_Coordinator::getInstance();

            $this->_initUrlDatas();
            $this->_initParams();
        }

        /**
         * Returns a boolean value indicating wether the response type is allowed
         *
         * @param       string      $responseClass : the name of a response class
         * @return      boolean
         */
        public function isAllowedResponse($responseClass)
        {
            if ($ar = $this->_allowedResponses()) {
                return in_array($responseClass, $ar);
            } else {
                return true;
            }
        }

	////////////////////////////////////////////////////////////////////////////
	//                            Protected Methods                           //
	////////////////////////////////////////////////////////////////////////////

        /**
         * Initializes the url properties
         *
         * throws       Core_Exception
         * @return      void
         */
        protected function _initUrlDatas()
        {
            if (isset($_SERVER[$this->_registry['config']->urlengine->scriptNameServerVariable])) {
                $this->_urlScript = $_SERVER[$this->_registry['config']->urlengine->scriptNameServerVariable];
            } else {
                $this->_urlScript = $_SERVER['SCRIPT_NAME'];
            }

            $lastslash = strrpos($this->_urlScript, '/');
            $this->_urlScriptPath = substr($this->_urlScript, 0, $lastslash)  .'/';

            if (empty($this->_registry['config']->urlengine->basePath)) {
                $this->_registry['config']->urlengine->basePath = $this->_urlScriptPath;

                if ($this->_registry['config']->urlengine->wwwpath{0} != '/') {
                    $this->_registry['config']->urlengine->wwwpath = $this->_urlScriptPath . $this->_registry['config']->urlengine->wwwpath;
                }
            } else if (strpos($this->_urlScriptPath, $this->_registry['config']->urlengine->basePath) !== 0) {
                throw new Core_Exception('Error: basePath ('. $this->_registry['config']->urlengine->basePath .') in config file doesn\'t correspond to current base path. You should set it to '. $this->_urlScriptPath);
            }

            $this->_urlScriptName = substr($this->_urlScript, $lastslash + 1);

            $piiqp = $this->_registry['config']->urlengine->pathInfoInQueryParameter;
            if ($piiqp) {
                if (isset($_GET[$piiqp])) {
                    $pathinfo = $_GET[$piiqp];
                    unset($_GET[$piiqp]);
                } else
                    $pathinfo = '';
            } else if (isset($_SERVER['PATH_INFO'])) {
                $pathinfo = $_SERVER['PATH_INFO'];
            } else if (isset($_SERVER['ORIG_PATH_INFO'])) {
                $pathinfo = $_SERVER['ORIG_PATH_INFO'];
            } else {
                $pathinfo = '';
            }

            //when php is used as cgi and if there isn't pathinfo in the url
            if ($pathinfo == $this->_urlScript) {
                $pathinfo = '';
            }

            //under IIS, we may get  /subdir/index.php/mypath/myaction as PATH_INFO, so we fix it
            if (Core_Helper_Environment::isWin32() && $pathinfo && strpos($pathinfo, $this->_urlScript) !== false) {
                $pathinfo = substr($pathinfo, strlen($this->_urlScript));
            }

            $this->_urlPathInfo = $pathinfo;
        }

		/**
		 * Returns a list of class name of allowed response corresponding to the request
		 *
		 * @return      boolean|array   the list, or false to allow everything
		 */
		protected function _allowedResponses()
		{
			return false;
		}

	////////////////////////////////////////////////////////////////////////////
	//                       Abstract Protected Methods                       //
	////////////////////////////////////////////////////////////////////////////

        /**
         * Initializes the parameters of the request
         */
        abstract protected function _initParams();
    }
